package per.hnvcam.common.impl;

import per.hnvcam.common.SubSetGenerator;

import java.util.HashSet;
import java.util.Set;

/**
 * Created by IntelliJ IDEA.
 * User: Vi Cam
 * Date: 31/01/2012
 * Time: 22:36
 * To change this template use File | Settings | File Templates.
 */
public class ReducedCombinationGeneratorImpl implements SubSetGenerator {

   private int setLength;
   private int subSetLength;
   private int maxSubSetCount;
   private Set<Integer> memberExistence;
   private Set<Entry> subSetExistence;
   private int subSetCount;

   public ReducedCombinationGeneratorImpl(int setLength, int subSetLength, int maxSubSetCount) {
      this.setLength = setLength;
      this.subSetLength = subSetLength;
      this.maxSubSetCount = maxSubSetCount;
      this.memberExistence = new HashSet<Integer>();
      this.subSetExistence = new HashSet<Entry>();
      subSetCount = 0;
   }

   @Override
   public void reset() {
      this.memberExistence.clear();
      this.subSetExistence.clear();
      subSetCount = 0;
   }

   @Override
   public boolean hasMore() {
      return subSetCount <= maxSubSetCount && memberExistence.size() < setLength;
   }

   @Override
   public int[] getNext() {
      int[] result = new int[subSetLength];
      boolean gotSubSet = false;
      while (!gotSubSet) {
         HashSet<Integer> valueExistence = new HashSet<Integer>();
         for (int i = 0; i < result.length; i++) {
            boolean gotValue = false;
            while (!gotValue) {
               int value = (int) Math.round(Math.random() * (setLength - 1));
               if (valueExistence.contains(value)) {
                  continue;
               }
               valueExistence.add(value);
               memberExistence.add(value);
               result[i] = value;
               gotValue = true;
            }
         }
         Entry thisEntry = new Entry(result);
         if (subSetExistence.add(thisEntry)) {
            gotSubSet = true;
            subSetCount++;
         }
      }
      return result;
   }

   private class Entry {
      Set<Integer> items;

      Entry(int[] value) {
         this.items = new HashSet<Integer>();
         for (int item : value) {
            this.items.add(item);
         }
      }

      @Override
      public boolean equals(Object object) {
         return this.items.equals(object);
      }

      @Override
      public int hashCode() {
         int result = 0;
         for (int item : this.items) {
            result += item;
         }
         return result;
      }
   }
}
